class Parser

prechigh
  nonassoc TkLBrackets TkRBrackets
  nonassoc TkLParenths TkRParenths
  nonassoc CALL
  nonassoc ID
  left TkDoubleAst
  nonassoc UMINUS TkDollar TkAt TkCaret
  left TkAsterisk TkSlash TkPercent TkDot
  right TkPlus TkMinus
  left TkLessThan TkGreaterThan TkLessEqual TkGreaterEqual TkEqual TkNotEqual
  nonassoc TkBang
  left TkDoubleAmp
  left TkDoublePipe
  right TkWIf TkWThen TkWElse # Se asocia el "else" al "if"-"then" más cercano.
  nonassoc TkAssign TkWRead NAWRITE TkWReturn
preclow

expect 0

token TkId TkNum TkString TkBooleano TkDot TkComma TkColon TkSemiColon 
      TkLParenths TkRParenths TkLBrackets TkRBrackets TkLBraces TkRBraces 
      TkPlus TkMinus TkAsterisk TkSlash TkPercent TkDoubleAst TkLessThan 
      TkGreaterThan TkLessEqual TkGreaterEqual TkEqual TkNotEqual TkDollar TkAt 
      TkCaret TkDoubleAmp TkDoublePipe TkBang TkAssign TkWNum TkWVec TkWMat 
      TkWVars TkWZeroes TkWRange TkWEye TkWDefine TkWOf TkWType TkWAs TkWBegin 
      TkWEnd TkWIf TkWThen TkWElse TkWWhile TkWDo TkWForEach TkWIn TkWRead 
      TkWWrite TkWReturn UMINUS CALL ID NAWRITE

rule

  target:
    PROGRAM  {result = @tree = AST.new(val[0])}
  ;

  PROGRAM:
    INST           {result = val[0]}
  | DEFILIST INST  {result = ASTStatement.new(nil, val[0], val[1])}
  ;

  DEFILIST:
    DEFINE           {result = val[0]}
  | DEFILIST DEFINE  {result = ASTStatement.new(nil, val[0], val[1])}
  ;

  DEFINE:
    TkWDefine TkId TkLParenths PARMLIST TkRParenths TkWOf TkWType TYPE TkWAs 
    INST  {result = ASTDeclaration.new("Define", val[1], val[3], val[7], val[9])}
  ;

  PARMLIST:
    /* λ */                {result = ["λ"]}
  | PARM                   {result = val[0]}
  | PARMLIST TkComma PARM  {result = ASTExpression.new("Comma", val[0], val[2])}
  ;

  PARM:
    TkId TkColon TYPE  {result = ASTExpression.new("Colon", val[0], val[2])}
  ;

  TYPE:
    TkWNum  {result = val[0]}
  | TkWVec  {result = val[0]}
  | TkWMat  {result = val[0]}
  ;

  INST:
    ASSIGN   {result = val[0]}
  | BLOCK    {result = val[0]}
  | IF       {result = val[0]}
  | WHILE    {result = val[0]}
  | FOREACH  {result = val[0]}
  | READ     {result = val[0]}
  | WRITE    {result = val[0]}
  | RETURN   {result = val[0]}
  ;

  ASSIGN:
    ARITEXPR TkAssign ARITEXPR  {result = ASTStatement.new("Assign", val[0], val[2])}
  ;

  ARITEXPR:
    TkId                         =ID  {result = ASTExpression.new("Variable", val[0])}
  | TkNum                             {result = ASTExpression.new("Number", val[0])}
  | VECORMAT                          {result = val[0]}
  | ARITOPER                          {result = val[0]}
  | FUNCCALL                   =CALL  {result = val[0]}
  | TkLParenths ARITEXPR TkRParenths  {result = ASTExpression.new("Association", val[1])}
  ;

  VECORMAT:
    TkLBraces LINORCOL TkRBraces  {result = ASTExpression.new("Vec/Mat", val[1])}
  ;

  LINORCOL:
    /* λ */                        {result = ["λ"]}
  | ARITEXPR                       {result = val[0]}
  | LINORCOL TkComma ARITEXPR      {result = ASTExpression.new("Comma", val[0], val[2])}
  | LINORCOL TkSemiColon ARITEXPR  {result = ASTExpression.new("SemiColon", val[0], val[2])}
  ;

  ARITOPER:
    TkMinus ARITEXPR      =UMINUS  {result = ASTExpression.new("Sig", val[1])}
  | TkDollar ARITEXPR              {result = ASTExpression.new("N_Lines", val[1])}
  | TkAt ARITEXPR                  {result = ASTExpression.new("N_Cols", val[1])}
  | ARITEXPR TkCaret               {result = ASTExpression.new("Tras", val[0])}
  | ARITEXPR TkPlus ARITEXPR       {result = ASTExpression.new("Add", val[0], val[2])}
  | ARITEXPR TkMinus ARITEXPR      {result = ASTExpression.new("Sub", val[0], val[2])}
  | ARITEXPR TkAsterisk ARITEXPR   {result = ASTExpression.new("Mult", val[0], val[2])}
  | ARITEXPR TkSlash ARITEXPR      {result = ASTExpression.new("Div", val[0], val[2])}
  | ARITEXPR TkPercent ARITEXPR    {result = ASTExpression.new("Mod", val[0], val[2])}
  | ARITEXPR TkDoubleAst ARITEXPR  {result = ASTExpression.new("Exp", val[0], val[2])}
  | ARITEXPR TkDot ARITEXPR        {result = ASTExpression.new("Dot", val[0], val[2])}
  | ACCORSEG                       {result = val[0]}
  ;

  ACCORSEG:
    ARITEXPR TkLBrackets CRDS TkRBrackets  {result = ASTExpression.new("Access", val[0], val[2])}
  ;

  CRDS:
    INDEX                {result = val[0]}
  | INDEX TkComma INDEX  {result = ASTExpression.new("Comma", val[0], val[2])}
  ;

  INDEX:
    ARITEXPR                   {result = val[0]}
  | SUBINDEX TkColon SUBINDEX  {result = ASTExpression.new("Box", val[0], val[2])}
  ;

  SUBINDEX:
    /* λ */   {result = ["λ"]}
  | ARITEXPR  {result = val[0]}
  ;

  FUNCCALL:
    TkId TkLParenths FUNCARGS TkRParenths      {result = ASTExpression.new("Call", val[0], val[2])}
  | FUNCNAME TkLParenths FUNCARGS TkRParenths  {result = ASTExpression.new("Call", val[0], val[2])}
  ;

  FUNCNAME:
    TkWZeroes  {result = val[0]}
  | TkWRange   {result = val[0]}
  | TkWEye     {result = val[0]}
  ;

  FUNCARGS:
    /* λ */                    {result = ["λ"]}
  | ARITEXPR                   {result = val[0]}
  | FUNCARGS TkComma ARITEXPR  {result = ASTExpression.new("Comma", val[0], val[2])}
  ;

  BOOLEXPR:
    TkBooleano                        {result = ASTBool.new("Booleano", val[0])}
  | BOOLOPER                          {result = val[0]}
  | TkLParenths BOOLEXPR TkRParenths  {result = ASTBool.new("Association", val[1])}
  ;

  BOOLOPER:
    TkBang BOOLEXPR                   {result = ASTBool.new("Not", val[1])}
  | ARITEXPR TkLessThan ARITEXPR      {result = ASTBool.new("Less_Than", val[0], val[2])}
  | ARITEXPR TkGreaterThan ARITEXPR   {result = ASTBool.new("Greater_Than", val[0], val[2])}
  | ARITEXPR TkLessEqual ARITEXPR     {result = ASTBool.new("Less_Equal", val[0], val[2])}
  | ARITEXPR TkGreaterEqual ARITEXPR  {result = ASTBool.new("Greater_Equal", val[0], val[2])}
  | ARITEXPR TkEqual ARITEXPR         {result = ASTBool.new("Equal", val[0], val[2])}
  | ARITEXPR TkNotEqual ARITEXPR      {result = ASTBool.new("Not_Equal", val[0], val[2])}
  | BOOLEXPR TkDoubleAmp BOOLEXPR     {result = ASTBool.new("And", val[0], val[2])}
  | BOOLEXPR TkDoublePipe BOOLEXPR    {result = ASTBool.new("Or", val[0], val[2])}
  | BOOLEXPR TkEqual BOOLEXPR         {result = ASTBool.new("Equal", val[0], val[2])}
  ;

  BLOCK:
    TkWBegin INSTLIST TkWEnd       {result = ASTStatement.new("Block", val[1])}
  | TkWBegin VARS INSTLIST TkWEnd  {result = ASTStatement.new("Block", val[1], val[2])}
  ;

  INSTLIST:
    INST                       {result = val[0]}
  | INSTLIST TkSemiColon INST  {result = ASTStatement.new("SemiColon", val[0], val[2])}
  ;

  VARS:
    TkWVars VARSLIST  {result = ASTStatement.new("Vars", val[1])}
  ;

  VARSLIST:
    VARSELEM                       {result = val[0]}
  | VARSLIST TkSemiColon VARSELEM  {result = ASTExpression.new("SemiColon", val[0], val[2])}
  ;

  VARSELEM:
    IDLIST TkColon TYPE  {result = ASTExpression.new("Colon", val[0], val[2])}
  ;

  IDLIST:
    TkId                 {result = ASTExpression.new("Variable", val[0])}
  | IDLIST TkComma TkId  {result = ASTExpression.new("Comma", val[0], val[2])}
  ;

  IF:
    TkWIf BOOLEXPR TkWThen INST               {result = ASTStatement.new("IfThen", val[1], val[3])}
  | TkWIf BOOLEXPR TkWThen INST TkWElse INST  {result = ASTStatement.new("IfElse", val[1], val[3], val[5])}
  ;

  WHILE:
    TkWWhile BOOLEXPR TkWDo INST  {result = ASTStatement.new("While", val[1], val[3])}
  ;

  FOREACH:
    TkWForEach TkId TkWIn ARITEXPR TkWDo INST  {result = ASTStatement.new("ForEach", val[1], val[3], val[5])}
  ;

  READ:
    TkWRead ARITEXPR  {result = ASTStatement.new("Read", val[1])}
  ;

  WRITE:
    TkWWrite EXPRLIST  {result = ASTStatement.new("Write", val[1])}
  ;

  EXPRLIST:
    EXPR                   {result = val[0]}
  | EXPRLIST TkComma EXPR  {result = ASTExpression.new("Comma", val[0], val[2])}
  ;

  EXPR:
    ARITEXPR  =NAWRITE  {result = val[0]}
  | TkString            {result = ASTExpression.new("String", val[0])}
  ;

  RETURN:
    TkWReturn ARITEXPR  {result = ASTStatement.new("Return", val[1])}
  ;

end

---- header ----
#--
# Proyecto Único (Etapa 2)
# Analizador Sintáctico
# 
# Autores:
# (Grupo R07)
# César Hernández (06-39724)
# Daniel Valera (07-41725)
# 
# Versión: 0.1
#++
# = Parser.rb
# Archivo generado por racc.

require 'AST'
require 'Exceptions'
require 'Lexer'

# = Clase Parser
# Clase compuesta por:
# <b>lexer</b>:: Cadena de caracteres o archivo del cual se lee el código.
# <b>token</b>:: Línea de código siendo leída.
---- inner ----

  attr_reader :lexer, :token, :tree
  
  # Inicializador de la clase.
  # <i><lexer</i>:: <DESCRIPCIÓN>
  def initialize(lexer)
    @lexer = lexer
    @token = nil
    @tree  = nil
  end

  # Método principal.
  def parse
    begin
      do_parse
      print_tree
    rescue ParserError => error
      puts error.reason
    end
  end

  # Método que permite imprimir el árbol generado.
  def print_tree
    puts @tree.to_s
  end

  # Método que devuelve al parser el siguiente token de la entrada.
  # <b>returns<b>:: <COMPLETAR>
  def next_token
    @token = @lexer.yylex()

    if @token == nil
      return [false,false]
    end

    return [:"#{@token.class}", @token.value]
  end

  # Método que especifica los pasos a seguir en caso de un error de sintáxis.
  def on_error(err_token_id, err_val, val_stack)
    raise ParserError.new(@token)
  end

---- footer ----

